package com.egor.views.components;

import com.egor.data.entity.Employee;
import com.egor.services.EmployeeService;
import com.egor.utils.ExcelGeneratorForEmployee;
import com.egor.views.components.modalboxes.EditEmployeeModalBox;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.provider.Query;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.spring.annotation.RouteScope;
import com.vaadin.flow.spring.data.VaadinSpringDataHelpers;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;
import org.vaadin.olli.FileDownloadWrapper;

import java.util.List;

@Component
@RouteScope
public class EmployeeComponent extends VerticalLayout {
    private final HorizontalLayout toolbar = new HorizontalLayout();
    private final Grid<Employee> grid = new Grid<>(Employee.class);
    private final TextField filterText = new TextField();
    private final Button addButton = new Button("Add employee");
    private final Button changeButton = new Button("Change employee");
    private final Button deleteButton = new Button("Delete employee");

    private final EmployeeService employeeService;
    private final EditEmployeeModalBox editEmployee;

    public EmployeeComponent(EmployeeService employeeService,
                             EditEmployeeModalBox editEmployee) {
        this.employeeService = employeeService;
        this.editEmployee = editEmployee;

        addClassName("employees-view");
        setSizeFull();
        setGrid();
        setToolbar();
        setModalBox();

        add(toolbar, grid);
    }

    private void setToolbar() {
        setButtons();
        setFilterText();

        toolbar.setWidthFull();
        toolbar.add(addButton, changeButton,
                deleteButton, gridExcelDownload(),
                gridPdfDownload(), filterText);
    }

    private void setModalBox() {
        editEmployee.addListener(EditEmployeeModalBox.SaveEvent.class, this::saveEmployee);
        editEmployee.addListener(EditEmployeeModalBox.CloseEvent.class, e -> closeEditor());
    }

    private void setGrid() {
        grid.setColumns("firstName", "secondName",
                        "lastName", "birthday");

        grid.setItems(query -> employeeService.listAll(
                PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query)))
                .stream());

        grid.asSingleSelect().addValueChangeListener(event ->
                editEmployee.setEmployee(event.getValue()));
    }

    private void setButtons() {
        addButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        deleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR);

        addButton.addClickListener(event -> addEmployee());
        changeButton.addClickListener(event -> editEmployee());
        deleteButton.addClickListener(event -> deleteEmployee());
    }

    private void setFilterText() {
        filterText.setPlaceholder("Search...");
        filterText.setClearButtonVisible(true);
        filterText.setValueChangeMode(ValueChangeMode.LAZY);
        filterText.addValueChangeListener(e -> updateList());
    }

    private FileDownloadWrapper gridExcelDownload() {
        List<Employee> employees = grid.getDataProvider().fetch(new Query<>()).toList();
        ExcelGeneratorForEmployee excelGeneratorForEmployee = new ExcelGeneratorForEmployee(employees);
        FileDownloadWrapper fileDownloadWrapper = new FileDownloadWrapper(new StreamResource("employees.xlsx",
                excelGeneratorForEmployee::generateExcelFile));

        Button button = new Button("Download Excel");
        fileDownloadWrapper.wrapComponent(button);
        return fileDownloadWrapper;
    }

    private FileDownloadWrapper gridPdfDownload() {
        List<Employee> employees = grid.getDataProvider().fetch(new Query<>()).toList();
        ExcelGeneratorForEmployee excelGeneratorForEmployee = new ExcelGeneratorForEmployee(employees);
        FileDownloadWrapper fileDownloadWrapper = new FileDownloadWrapper(new StreamResource("employees.pdf",
                excelGeneratorForEmployee::generatePdfFile));

        Button button = new Button("Download PDF");
        fileDownloadWrapper.wrapComponent(button);
        return fileDownloadWrapper;
    }

    private void saveEmployee(EditEmployeeModalBox.SaveEvent event) {
        employeeService.save(event.getEmployee());
        updateList();
        closeEditor();
    }

    private void deleteEmployee() {
        Employee employee = grid.asSingleSelect().getValue();

        if (employee != null) {
            employeeService.delete(employee);
            updateList();
        }
    }

    public void editEmployee() {
        editEmployee.open();
    }

    private void addEmployee() {
        grid.asSingleSelect().clear();
        editEmployee.setEmployee(new Employee());
        editEmployee.open();
    }

    private void closeEditor() {
        editEmployee.setEmployee(null);
        editEmployee.close();
    }

    private void updateList() {
        grid.setItems(query -> employeeService.findAll(filterText.getValue(),
                        PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query)))
                .stream());
    }
}
